﻿using NUnit.Framework;
using Tycho.Parser.Peg;

namespace Tycho.Parser.Tests.Peg {
    [TestFixture]
    public class ChoiceRuleSpecification {
        [Test]
        public void ParseShouldSucceedIfFirstOfTwoRulesSucceeds () {
            var source = "a";

            var choice = new ChoiceRule (new KeywordRule ("a"), new KeywordRule ("b"));

            var result = choice.Parse (source, 0, new ParseContext ());

            Assert.IsNotNull (result);
            Assert.AreEqual (1, result.Index);
        }

        [Test]
        public void ParseShouldSucceedIfSecondOfTwoRulesSucceeds () {
            var source = "b";

            var choice = new ChoiceRule (new KeywordRule ("a"), new KeywordRule ("b"));

            var result = choice.Parse (source, 0, new ParseContext ());

            Assert.IsNotNull (result);
            Assert.AreEqual (1, result.Index);
        }

        [Test]
        public void ParseShouldFailIfNoRuleSucceeds () {
            var source = "c";

            var choice = new ChoiceRule (new KeywordRule ("a"), new KeywordRule ("b"));

            var result = choice.Parse (source, 0, new ParseContext ());

            Assert.IsNull (result);
        }

        [Test]
        public void ParseShouldReturnCorrectIndexForMatchedPattern1 () {
            var source = "a b";

            var choice = new ChoiceRule (new SequenceRule (new KeywordRule ("a"), new KeywordRule ("b")), new KeywordRule ("c"));

            var result = choice.Parse (source, 0, new ParseContext ());

            Assert.IsNotNull (result);
            Assert.AreEqual (3, result.Index);
        }

        [Test]
        public void ParseShouldReturnCorrectIndexForMatchedPattern2 () {
            var source = "c d";

            var choice = new ChoiceRule (new SequenceRule (new KeywordRule ("a"), new KeywordRule ("b")), new KeywordRule ("c"));

            var result = choice.Parse (source, 0, new ParseContext ());

            Assert.IsNotNull (result);
            Assert.AreEqual (1, result.Index);
        }

        [Test]
        public void ParseShouldOnlyTakeSuccessfulContext () {
            var source = "b";

            var a = IdentifierKeywordProduction.CreateTerminal ("a");
            var wrongContext = new ParseContext ();
            a.ResultTransform = r => {
                                    r.Context = wrongContext;
                                    return r;
                                };
            var b = IdentifierKeywordProduction.CreateTerminal ("b");
            var rightContext = new ParseContext ();
            b.ResultTransform = r => {
                                    r.Context = rightContext;
                                    return r;
                                };
            var choice = new ChoiceRule (new LiteralRule (a), new LiteralRule (b));

            var result = choice.Parse (source, 0, new ParseContext ());

            Assert.IsNotNull (result);
            Assert.AreEqual (1, result.Index);
            Assert.AreEqual (rightContext, result.Context);
        }

        [Test]
        public void ParseShouldOnlyCaptureSuccessfulRule () {
            var source = "x a";

            var choice = new ChoiceRule (new NamedRule ("a", new NonTerminal ("x-rule", new SequenceRule (new KeywordRule ("x"), new KeywordRule ("y")))), new NamedRule ("b", IdentifierProduction.CreateTerminal ()));

            var result = choice.Parse (source, 0, new ParseContext ());

            Assert.IsNotNull (result);
            Assert.AreEqual (1, result.Index);

            Assert.AreEqual (1, result.Captures.Count);
            result.AssertCaptureIs (0, "b", "x");
        }
    }
}